package server.comm;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;

import server.controller.Controller;

import messaage.AddForumMsg;
import messaage.AddFriendMsg;
import messaage.AddPostMsg;
import messaage.ConnectMsg;
import messaage.ConnectedMsg;
import messaage.CreateThreadMsg;
import messaage.DisconnectMsg;
import messaage.DisconnectedMsg;
import messaage.ErrorMsg;
import messaage.GetForumTopicsMsg;
import messaage.GetFriendsListMsg;
import messaage.GetListOfForumsMsg;
import messaage.GotListOfForumsMsg;
import messaage.LoggedInMsg;
import messaage.LoginMsg;
import messaage.LogoutMsg;
import messaage.Message;
import messaage.RegisterMsg;
import messaage.RemoveFriendMsg;
import messaage.GetThreadMsg;


public class ForumProtocol implements ServerProtocol {

	private ArrayList<ClientStub> users;
	private Controller controller;
    private boolean _shouldClose;


	public ForumProtocol() {
		users = new ArrayList<ClientStub>();
		controller = new Controller();
		controller.readFromXML();
	}

    public boolean shouldClose() {
        return _shouldClose;
    }
    public void connectionTerminated() {
        _shouldClose = true;
    }

	public String processMessage(String msg, ClientStub client, ConnectionHandler ch) {
		String str ="";
        if (msg != null) {
            if (isEnd(msg))
                _shouldClose = true;
            else {

		try {

		Message sMsg = Message.fromString(msg);
		System.out.println(sMsg.toString());

		if(sMsg instanceof ConnectMsg) {
			if(!client.isConnected)
			str = processConnect(sMsg, client);
			else {
				ErrorMsg err = new ErrorMsg("", "client is already connected");
				return err.toString();
			}
		} else if(sMsg instanceof DisconnectMsg) {
			if(client.isConnected) {
				str = processDisconnect(sMsg,client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof RegisterMsg) {
			if(client.isConnected) {
				str = processRegister(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof LoginMsg) {
			if(client.isConnected) {
				str = processLogin(sMsg, client, ch);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof LogoutMsg) {
			if(client.isConnected) {
				str = processLogout(sMsg, client, ch);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof AddFriendMsg) {
			if(client.isConnected) {
				str = processAddFriend(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof RemoveFriendMsg) {
			if(client.isConnected) {
				str = processRemoveFriend(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof AddForumMsg) {
			if(client.isConnected) {
				str = processAddForum(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof GetListOfForumsMsg) {
			if(client.isConnected) {
				str = processForumsListReq(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof GetForumTopicsMsg) {
			if(client.isConnected) {
				str = processForumTopicsMsg(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof CreateThreadMsg) {
			if(client.isConnected) {
				str = processCreateThread(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof AddPostMsg) {
			if(client.isConnected) {
				str = processAddPostMsg(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		}else if(sMsg instanceof GetThreadMsg) {
			if(client.isConnected) {
				str = processGetThreadsMsg(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else if(sMsg instanceof GetFriendsListMsg) {
			if(client.isConnected) {
				str = processGetFriendsListMsg(sMsg, client);
			} else {
				ErrorMsg err = new ErrorMsg("", "client has not connected yet");
				return err.toString();
			}
		} else {
			ErrorMsg err = new ErrorMsg("", "Bad command");
			return err.toString();
		}
		}
		catch (Exception e) {
			return e.toString();
		}
            }
        }
        controller.saveToXML();
		return str;

	}
	public synchronized String  processConnect(Message sMsg, ClientStub client) {
		UUID sessionID = UUID.randomUUID();
		users.add(client);
		client.setConnected(true);
		ConnectedMsg msg = new ConnectedMsg("", sessionID.toString());
		return msg.toString();
	}

	public synchronized String processDisconnect(Message sMsg, ClientStub client) {
		if(client.isConnected) {
			client.setConnected(false);
			client.send(new DisconnectedMsg(""));
			users.remove(client);
			try {
				client.getClientSocket().close();
			} catch(IOException e) {
				System.out.println(e.getMessage());
			}
			users.remove(client);
		}
		return null;

	}

	public synchronized String  processLogin(Message sMsg, ClientStub client, ConnectionHandler ch) {
		if(client.isLoogedIn()) {
			ErrorMsg err = new ErrorMsg("", "User is already logged in with username: " +
					 client.getClientName());
			return err.toString();
		}
		Message m = controller.getLoginMsg((LoginMsg)sMsg);
		if(m instanceof LoggedInMsg) {
			client.setClientName(((LoginMsg)sMsg).getUsername());
			client.setLoogedIn(true);
			this.controller.addLoggedIn(ch);
		}
		return m.toString();
	}

	public synchronized String  processLogout(Message sMsg, ClientStub client, ConnectionHandler ch) {
		client.setLoogedIn(false);
		LogoutMsg tmpM = new LogoutMsg(client.getClientName());
		Message m = controller.getLogoffMsg(tmpM);
		this.controller.removeLoggedIn(ch);
		return m.toString();
	}

	public synchronized String  processRegister(Message sMsg, ClientStub client) {
		Message m = controller.getRegisterMsg((RegisterMsg)sMsg);
		return m.toString();
	}

	public synchronized String  processAddFriend(Message sMsg, ClientStub client) {
		AddFriendMsg tmpM = new AddFriendMsg(client.getClientName(), ((AddFriendMsg)sMsg).getNameOfFriend());
		Message m = controller.getAddUserFriendMsg(tmpM);
		return m.toString();
	}

	public synchronized String  processRemoveFriend(Message sMsg, ClientStub client) {
		RemoveFriendMsg tmpM = new RemoveFriendMsg(client.getClientName(), ((RemoveFriendMsg)sMsg).getNameOfFriend());
		Message m = controller.getRemoveUserFriendMsg(tmpM);
		return m.toString();
	}

	public synchronized String  processAddForum(Message sMsg, ClientStub client) {
		AddForumMsg tmpM = new AddForumMsg(client.getClientName(), ((AddForumMsg)sMsg).getSubject());
		Message m = controller.getAddForumMsg(tmpM);
		return m.toString();
	}

	public synchronized String  processForumsListReq(Message sMsg, ClientStub client) {
		GetListOfForumsMsg tmpM = new GetListOfForumsMsg(client.getClientName());
		Message m = controller.ForumsListReq(tmpM);
		GotListOfForumsMsg g = (GotListOfForumsMsg)m;
		return (g.toString());
	}

	public synchronized String  processForumTopicsMsg(Message sMsg, ClientStub client) {
		GetForumTopicsMsg tmpM = new GetForumTopicsMsg(client.getClientName(),
				Integer.toString(((GetForumTopicsMsg)sMsg).getForumID()));
		Message m = controller.getForumsTopicsMsg(tmpM);
		return m.toString();
	}

	public synchronized String  processCreateThread(Message sMsg, ClientStub client) {
		CreateThreadMsg tmpM = new CreateThreadMsg(client.getClientName(),
				Integer.toString(((CreateThreadMsg)sMsg).getForumID()),
				((CreateThreadMsg)sMsg).getTopicName(),
				((CreateThreadMsg)sMsg).getBody());
		Message m = controller.getCreateThread(tmpM);
		return m.toString();
	}

	public synchronized String  processAddPostMsg(Message sMsg, ClientStub client) {
		AddPostMsg tmpM = new AddPostMsg(client.getClientName(),
				Integer.toString(((AddPostMsg)sMsg).getForumID()),
			//	Integer.toString(((AddPostMsg)sMsg).getThreadID()),
				Integer.toString(((AddPostMsg)sMsg).getPostID()),
				((AddPostMsg)sMsg).getTopicName(),
				((AddPostMsg)sMsg).getBody());
		Message m = controller.getAddPostMsg(tmpM);
		return m.toString();
	}

	public synchronized String  processGetThreadsMsg(Message sMsg, ClientStub client) {
		GetThreadMsg tmpM = new GetThreadMsg(client.getClientName(),
				Integer.toString(((GetThreadMsg)sMsg).getForumID()),
				Integer.toString(((GetThreadMsg)sMsg).getThreadID()));
		Message m = controller.getThreadOfForum(tmpM);
		return m.toString();
	}
	
	public synchronized String  processGetFriendsListMsg(Message sMsg, ClientStub client) {
		GetFriendsListMsg tmpM = new GetFriendsListMsg(sMsg.getUsername());
		Message m = controller.getFriendsList(tmpM);
		System.out.println(m.toString());
		return m.toString();
	}

	public boolean isEnd(String msg) {
		return msg.equals("byeserver");

	}

	/////// Private functions //////////
}
